#include "GameBoard.h"
#include "GamePiece.h"
#include <cstddef>
#include <format>
#include <stdexcept>
#include <utility>

template <typename T>
Grid<T>::Grid(size_t width, size_t height) : m_width{width}, m_height{height} {
  m_cells.resize(m_width);
  for (auto &column : m_cells) {
    column.resize(m_height);
  }
}
template <typename T>
Grid<T>::Grid(const Grid<T> &src) : Grid<T>(src.m_width, src.m_height) {
  for (size_t i{0}; i < m_width; ++i) {
    for (size_t j{0}; j < m_height; ++j) {
      m_cells[i][j] = src.m_cells[i][j];
    }
  }
}
template <typename T> void Grid<T>::verifyCoordinate(size_t x, size_t y) const {
  if (x >= m_width) {
    throw std::out_of_range(
        std::format("{} must be less than {},", x, m_width));
  }

  if (y >= m_height) {
    throw std::out_of_range(
        std::format("{} must be less than {},", y, m_height));
  }
}
template <typename T> void Grid<T>::swap(Grid<T> &other) noexcept {
  std::swap(m_width, other.m_width);
  std::swap(m_height, other.m_height);
  std::swap(m_cells, other.m_cells);
}
template <typename T> void swap(Grid<T> &first, Grid<T> &second) noexcept {
  first.swap(second);
}
template <typename T> Grid<T> &Grid<T>::operator=(const Grid<T> &src) {
  Grid temp{src};
  swap(temp);
  return *this;
}
template <typename T> std::optional<T> &Grid<T>::at(size_t x, size_t y) {
  verifyCoordinate(x, y);
  //   return const_cast<std::unique_ptr<GamePiece> &>(
  //       (std::as_const(*this).at(x, y)));
  return m_cells[x][y];
}
template <typename T>
const std::optional<T> &Grid<T>::at(size_t x, size_t y) const {
  verifyCoordinate(x, y);
  return m_cells[x][y];
}